home *** CD-ROM | disk | FTP | other *** search
/ MACD 5 / MACD 5.bin / workbench / tools / czesc_1 / dr / source / purify.a < prev    next >
Text File  |  1994-02-23  |  9KB  |  248 lines

  1. * This here is startup code for Amiga Aztec C programs, to make them pure.
  2. * Assemble it with the command "as purify.a" and link the resulting purify.o
  3. * file with your C program, in some manner like "ln yourprogram.o purify.o -lc",
  4. * and your program can then be marked as pure, and made resident, IF it meets
  5. * certain conditions:
  6. * 1) You must not use the large data model for accessing your global variables.
  7. * 2) You MUST NOT call the geta4() function from within any part of your program
  8. * that is run outside of your main process.  Subtasks, interrupt handlers, and
  9. * wedges installed with SetFunction may not use geta4, and thus may not access
  10. * your global variables by any direct method.  Note that #pragma intfunc causes
  11. * an implicit call of geta4().
  12. * 3) You must not initialize global variables using the addresses of other
  13. * global variables.  For example, the following is not correct:
  14. *     char foo[100], bar[100];
  15. *     char *foobar[2] = { foo, bar };        /* WRONG */
  16. * If you do this, then any references to foobar[0] will end up accessing
  17. * DIFFERENT MEMORY than accessing foo directly will.  Instead, you have to do
  18. * such initialization in the code, with statements like "foobar[0] = foo;
  19. * foobar[1] = bar;".
  20. *
  21. * 4) You must not use detach.o -- this applies to ALL pure programs, not just
  22. * those that use this startup code.
  23. * 5) Do not use this when making a shared library or device driver.  ("Duh...")
  24. * This was originally based on resident.asm by Olaf Barthel, which is available
  25. * on fish disk 396, but does not contain any of his code.  Barthel's version had
  26. * serious errors in it, and will not work in many cases.  It was also a lot less
  27. * efficient than the method I use.
  28. *
  29. * With the Aztec assembler, do not use the -N flag (one pass), because there's
  30. * a bug that makes the ENTRY directive not work with that option.  It will need
  31. * a few changes in syntax to work with other assemblers.  It might be possible
  32. * to make versions for other C compilers, so I've labeled everything which I
  33. * know to be Aztec specific with a comment containing the word "Aztec".
  34. *
  35. * The one possibly not quite cool bit of programming used here is that I used
  36. * SysBase->ThisTask instead of FindTask(0), in several places.  If they ever
  37. * make an Amiga that runs tasks on several CPUs at once, that might break.
  38. * This is by Paul Kienitz, 1 December 1991, placed in the public domain.
  39. * Revised 11 March 1992 to remove mistake -- DOSBase was accessed after the
  40. * memory it was in was already freed.  A couple other little changes.  Some
  41. * changes to this comment, but not to the code, were made later.
  42.  
  43.  
  44. ; We avoid pulling in include files by copying a few definitions here:
  45.  
  46. MEMB_FAST    equ    2        ; exec/memory.i
  47. MEMB_CLEAR    equ    16        ; exec/memory.i
  48. ThisTask    equ    276        ; exec/execbase.i
  49. AttnFlags    equ    296        ; exec/execbase.i
  50. AFB_68881    equ    4        ; exec/execbase.i
  51. AG_OpenLib    equ    $30000        ; exec/alerts.i
  52. AO_DOSLib    equ    $8007        ; exec/alerts.i
  53. pr_ReturnAddr    equ    176        ; libraries/dosextens.i
  54. pr_CLI        equ    172        ; libraries/dosextens.i
  55. pr_MsgPort    equ    92        ; libraries/dosextens.i
  56.  
  57. _LVOTypeOfMem        equ    -534
  58. _LVOAllocMem        equ    -198
  59. _LVOOldOpenLibrary    equ    -408
  60. _LVOAlert        equ    -108
  61. _LVOSupervisor        equ    -30
  62. _LVOFreeMem        equ    -210
  63. _LVOCloseLibrary    equ    -414
  64. _LVOWaitPort        equ    -384
  65. _LVOGetMsg        equ    -372
  66. _LVOReplyMsg        equ    -378
  67. _LVOForbid        equ    -132
  68.  
  69.  
  70. lcall        macro
  71.         jsr    _LVO\1(a6)
  72.         endm
  73.  
  74. AbsExecBase    equ    (4).w
  75.  
  76.         xdef    .begin,_geta4
  77.         xref    __main,_SysBase,_DOSBase
  78.         xref    __savsp                    ; Aztec
  79. ;;        xdef    entree,cleanup        ; for debugging
  80.  
  81. ; the use of the label ".begin" for the entry point is an Aztec-ism
  82.         entry    .begin
  83.  
  84. .begin:
  85. entree:
  86.         far    data                    ; Aztec
  87.         lea    __H1_org+32766,a4    ; to access original globals
  88.  
  89.         lea    __H1_end,a1        ; Aztec; end of initialized data
  90.         lea    __H2_org,a2        ; Aztec; start of BSS
  91.         near    data                    ; Aztec
  92.  
  93.         cmp.l    a1,a2            ; the same address?
  94.         bne    bomb            ; if not, refuse to run
  95.  
  96.         move.l    a0,d6            ; save command arg-line pointer
  97.         move.l    d0,d5            ; save command arg length
  98.  
  99.         lea    __H1_org,a1        ; Aztec; start of data hunk
  100.         move.l    AbsExecBase,a6
  101.         lcall    TypeOfMem        ; what kind of ram is it in?
  102.         bclr.l    #MEMB_FAST,d0        ; do NOT force fast ram!
  103.         bset.l    #MEMB_CLEAR,d0        ; do force cleared memory
  104.  
  105.         move.l    d0,d1            ; memory type requirements
  106.         move.l    #(__H2_end-__H1_org),d0    ; Aztec; size of all globals
  107.         lcall    AllocMem        ; space for a complete copy
  108.         tst.l    d0
  109.         beq    bomb            ; if it failed, don't run
  110.         move.l    d0,a2
  111.  
  112.         lea    __H1_org,a0        ; Aztec; address of old globals
  113.         move.l    a2,a1            ; address of new globals
  114.         move.l    #((__H1_end-__H1_org)/4)-1,d0    ; Aztec; size to copy
  115. copyit:        move.l    (a0)+,(a1)+        ; copy all initialized data
  116.         dbra    d0,copyit
  117.  
  118. * Here's where we get tricky.  We need to put the address of our dublicated
  119. * global variable space someplace where it can be found by geta4(), and we need
  120. * to make sure that we free the copied globals no matter how the program exits.
  121. * What we do is save the pointer on the stack, and then make it appear that the
  122. * final exit address that the program must return to is the address of our
  123. * cleanup routine.  To do this, after pushing the pointer to the copied globals,
  124. * we push the size of the remaining available stack (12 bytes less than the
  125. * original size) and then the address of the cleanup code.  We set the variable
  126. * __savsp to point to that cleanup code address, so that the Aztec exit()
  127. * function will return to that point.  We set the pr_ReturnAddr field of our
  128. * struct Process to point one longword above that, to make the dos.library
  129. * Exit() function return to the cleanup code.  This is also used by geta4() to
  130. * locate the saved pointer to the copied globals.
  131.  
  132.         move.l    a2,-(sp)        ; where geta4() can find it
  133.         move.l    8(sp),a0        ; original size of the stack
  134.         sub.w    #12,a0            ; minus space we're using
  135.         move.l    a0,-(sp)        ; make stack look smaller
  136.         move.l    ThisTask(a6),a0        ; equivalent to FindTask(0)
  137.         move.l    sp,pr_ReturnAddr(a0)    ; for geta4() and dos Exit()
  138.         pea    cleanup            ; so everybody goes there
  139.  
  140. * The stack now looks like this:
  141. *
  142. *     Stack size in bytes        <-  old pr_ReturnAddr pointed here
  143. *     Return address for final exit    <-  __savsp would have pointed here
  144. *     Pointer to globals for geta4    <-  also used by cleanup
  145. *     New stack size, minus twelve    <-  new pr_ReturnAddr points here
  146. *     Fake return address: cleanup    <-  __savsp will point here
  147. *
  148. * Once __main is called, there will also be these:
  149. *
  150. *     Command line arg address    <-  argument to __main
  151. *     Command line arg length        <-  argument to __main ...SP is now here
  152. *     Return address to this module    <-  falls through to cleanup
  153.  
  154.         bsr    _geta4            ; use new globals
  155.         move.l    sp,__savsp        ; Aztec; exit() and stack check
  156.         move.l    a6,_SysBase        ; set up base for C program
  157.         lea    dosname,a1
  158.         lcall    OldOpenLibrary        ; open dos.library
  159.         move.l    d0,_DOSBase        ; set up another base
  160.         bne    dosokay
  161.         move.l    #AG_OpenLib!AO_DOSLib,d7    ; recoverable - no dos
  162.         lea    ThisTask(a6),a5        ; make it show our task adr
  163.         lcall    Alert            ; frighten the user
  164.         moveq    #127,d0            ; return value
  165.         rts                ; "returns" to cleanup
  166.  
  167. dosokay:    btst.b    #AFB_68881,AttnFlags+1(a6)    ; is there an FPU?
  168.         beq    nofpu
  169.         lea    resetfpu,a5
  170.         lcall    Supervisor        ; reset it in supervisor mode
  171.  
  172. nofpu:        movem.l    d5/d6,-(sp)        ; pass arguments to _main()
  173.         jsr    __main            ; RUN THE PROGRAM!
  174.         add.w    #12,sp            ; simulate rts to cleanup
  175.  
  176. cleanup:    move.l    d0,d7            ; set aside the return value
  177.         bsr    _geta4            ; so we can check DOSBase
  178.         move.l    AbsExecBase,a6
  179.         move.l    _DOSBase,a1
  180.         move.l    a1,d0            ; fake tst.l a1
  181.         beq    dosneveropen        ; was there ever a DOSBase?
  182.         lcall    CloseLibrary        ; if yes, close it
  183.  
  184. dosneveropen:    move.l    4(sp),a1        ; address of copied globals
  185.         move.l    #(__H2_end-__H1_org),d0    ; size of copied globals
  186.         lcall    FreeMem            ; get rid of the copy
  187.         addq    #8,sp            ; restore primordial stack
  188.         move.l    ThisTask(a6),a1
  189.         lea    4(sp),a0        ; just to be paranoid...
  190.         move.l    a0,pr_ReturnAddr(a1)    ; restore old pr_ReturnAddr
  191.  
  192.         move.l    d7,d0            ; restore the return value
  193.         rts                ; goodbye cruel world
  194.  
  195.  
  196. bomb:        move.l    AbsExecBase,a6        ; come here if we can't run
  197.         move.l    ThisTask(a6),a0
  198.         tst.l    pr_CLI(a0)        ; are we a Workbench process?
  199.         bne    noworkbench        ; if yes, then we need to
  200.                         ;   reply the startup message:
  201.         lea    pr_MsgPort(a0),a0
  202.         move.l    a0,a3            ; remember our msgport address
  203.         lcall    WaitPort        ; here come de message
  204.         move.l    a3,a0
  205.         lcall    GetMsg            ; got it
  206.         move.l    d0,a3            ; yes, remember it
  207.         lcall    Forbid            ; standard shutdown procedure
  208.         move.l    a3,a1
  209.         lcall    ReplyMsg        ; tell WB to unload us
  210.  
  211. noworkbench:    moveq    #127,d0            ; largest convenient return code
  212.         rts                ; might return to cleanup
  213.  
  214.  
  215.         mc68881        ; Aztec; activate FPU instruction opcodes
  216.  
  217. resetfpu:    clr.l    -(sp)            ; call this in supervisor mode
  218.         frestore (sp)+            ; reset the FPU
  219.         rte                ; return to user mode
  220.  
  221.  
  222. * Here's our magic routine to set up a4 for accessing the copied globals.
  223. * CALL ONLY FROM WITHIN THE SAME PROCESS.
  224.  
  225. _geta4:        move.l    AbsExecBase,a4
  226.         move.l    ThisTask(a4),a4
  227.         move.l    pr_ReturnAddr(a4),a4    ; ptr to FAKE stack size
  228.         move.l    4(a4),a4        ; stored ptr to copied globals
  229.         lea    32766(a4),a4        ; add the offset
  230.         rts
  231.  
  232. dosname:    dc.b    'dos.library',0        ; for OldOpenLibrary
  233.  
  234.         dseg                ; Aztec
  235. ; Assembler bug:  If you declare __H1_org public within the code segment,
  236. ; then the assembler refers to it with small data even if you have told
  237. ; it to use large data.  Hence the above dseg is necessary.  This does not seem
  238. ; to happen with ordinary symbols, just the __Hx_xxx ones.
  239.         public    __H1_org,__H1_end,__H2_org,__H2_end    ; Aztec
  240.